{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from keras.layers import *\n",
    "from keras.models import *\n",
    "from make_parallel import make_parallel"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "MODEL_FILENAME = 'model.h5'\n",
    "\n",
    "characters = '0123456789+-*() '\n",
    "width, height, n_len, n_class = 180, 60, 7, len(characters) + 1\n",
    "\n",
    "from keras import backend as K\n",
    "\n",
    "def ctc_lambda_func(args):\n",
    "    y_pred, labels, input_length, label_length = args\n",
    "    y_pred = y_pred[:, 2:, :]\n",
    "    return K.ctc_batch_cost(labels, y_pred, input_length, label_length)\n",
    "\n",
    "rnn_size = 128\n",
    "\n",
    "input_tensor = Input((width, height, 3))\n",
    "x = input_tensor\n",
    "for i in range(3):\n",
    "    x = Conv2D(32*2**i, (3, 3))(x)\n",
    "    x = BatchNormalization()(x)\n",
    "    x = Activation('relu')(x)\n",
    "    x = Conv2D(32*2**i, (3, 3))(x)\n",
    "    x = BatchNormalization()(x)\n",
    "    x = Activation('relu')(x)\n",
    "    x = MaxPooling2D(pool_size=(2, 2))(x)\n",
    "\n",
    "conv_shape = x.get_shape()\n",
    "x = Reshape(target_shape=(int(conv_shape[1]), int(conv_shape[2]*conv_shape[3])))(x)\n",
    "\n",
    "x = Dense(128)(x)\n",
    "x = BatchNormalization()(x)\n",
    "x = Activation('relu')(x)\n",
    "\n",
    "gru_1 = GRU(rnn_size, return_sequences=True, name='gru1')(x)\n",
    "gru_1b = GRU(rnn_size, return_sequences=True, go_backwards=True, \n",
    "             name='gru1_b')(x)\n",
    "gru1_merged = add([gru_1, gru_1b])\n",
    "\n",
    "gru_2 = GRU(rnn_size, return_sequences=True, name='gru2')(gru1_merged)\n",
    "gru_2b = GRU(rnn_size, return_sequences=True, go_backwards=True, \n",
    "             name='gru2_b')(gru1_merged)\n",
    "x = concatenate([gru_2, gru_2b])\n",
    "x = Dropout(0.25)(x)\n",
    "x = Dense(n_class, activation='softmax')(x)\n",
    "base_model = Model(input=input_tensor, output=x)\n",
    "\n",
    "base_model_parallel = make_parallel(base_model, 4)\n",
    "\n",
    "labels = Input(name='the_labels', shape=[n_len], dtype='float32')\n",
    "input_length = Input(name='input_length', shape=(1,), dtype='int64')\n",
    "label_length = Input(name='label_length', shape=(1,), dtype='int64')\n",
    "loss_out = Lambda(ctc_lambda_func, name='ctc')([base_model_parallel.output, labels, input_length, label_length])\n",
    "\n",
    "model = Model(inputs=(input_tensor, labels, input_length, label_length), outputs=loss_out)\n",
    "model.compile(loss={'ctc': lambda y_true, y_pred: y_pred}, optimizer='adam')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "model.load_weights('model_gru_best.h5')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "model2 = Model(inputs=input_tensor, outputs=x)\n",
    "model2.save('model.h5', overwrite=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
